<template>
  <div class="filter-setting-form" :class="showFormTitleLine ? 'fix' : ''">
    <a-form
      ref="form"
      :form="form"
      :label-col="{ span: labelCol }"
      :wrapper-col="{ span: wrapperCol }"
    >
      <div
        v-if="panelList.length > 0"
        class="panel-title"
        @click="showFlag = !showFlag"
      >
        <div v-if="showFormTitleLine" class="panel-title-hr"></div>
        {{ formTitle }}
        <a-icon :type="showFlag ? 'down' : 'right'" />
      </div>
      <div v-show="showFlag">
        <div v-for="(panel, index) in panelList" :key="index" class="panel">
          {{ panel.label }}
          <template v-for="(item, i) in panel.children">
            <a-form-item
              v-show="
                !item.showFunc ||
                (item.showFunc && item.showFunc(formData, panel.children))
              "
              :key="`form-item-${i}`"
              :label="item.label"
              :layout="item.layout"
              :class="item.layout"
            >
              <component
                :is="getCompType(item)"
                v-decorator="getDecorator(item)"
                v-bind="{ ...item.props, ...commonFormProps }"
                :props="item.props"
              >
              </component>
            </a-form-item>
          </template>
        </div>
      </div>
    </a-form>
  </div>
</template>

<script lang="ts">
/* eslint-disable unicorn/prevent-abbreviations */
import { Vue, Prop, Component, Watch } from 'vue-property-decorator'
import {
  dynamicCompMaps,
  dynamicComponent,
} from '@/components/common/VisualizationDashboard/util'
import { isEqual } from 'lodash'

export interface KeyValue {
  [key: string]: any
}

@Component({
  components: {
    ...dynamicComponent,
  },
})
export default class PropertyForm extends Vue {
  @Prop({ default: () => [] }) panelList!: KeyValue[]

  @Prop({ default: () => false })
  showFormTitleLine!: boolean

  @Prop({ default: () => 'formTitle' })
  formTitle!: string
  @Prop({
    type: Number,
    required: false,
    default() {
      return 8
    },
  })
  labelCol!: number

  @Prop({
    type: String,
    required: true,
    default: () => '',
  })
  formName!: string

  @Prop({
    type: Number,
    required: false,
    default() {
      return 16
    },
  })
  wrapperCol!: number

  @Prop({
    type: Object,
    required: true,
    default(): KeyValue {
      return {}
    },
  })
  formData!: KeyValue

  private form: any
  private commonFormProps = {
    size: 'small',
  }

  private showFlag: boolean = true // 是否展开面板

  beforeCreate() {
    const that = this
    this.form = this.$form.createForm(this, {
      name: `formName_${Math.random().toString().slice(2, 11)}`,
      // @ts-ignore
      onValuesChange: (formEle, changedValues, allValues) => {
        if (!that.checkEq(changedValues, that.formData)) {
          this.onFormValueChange(allValues)
        }
      },
    })
    // @ts-ignore
    window._form = this.form
  }

  checkEq(
    changedValues: { [key: string]: any },
    formData: { [key: string]: any }
  ) {
    return Object.keys(changedValues).reduce((rec: boolean, key: string) => {
      if (rec) {
        rec = isEqual(changedValues[key], formData[key])
      }
      return rec
    }, true)
  }

  @Watch('formData', { immediate: true, deep: true })
  private onFormDataChange(newValue: KeyValue, oldValue: KeyValue) {
    if (isEqual(newValue, oldValue)) {
      return
    }
    this.setFormData()
  }

  /**
   * 设置表单 form 的值
   */
  private setFormData() {
    if (!this.form) {
      return
    }
    const {
      form: { getFieldsValue, setFieldsValue },
      formData,
    } = this
    this.$nextTick(() => {
      const values = getFieldsValue()
      const formDataKeysSet = new Set(Object.keys(formData))
      // 设置值时只能设定表单中有的字段
      Object.keys(values).forEach((k) => {
        if (formDataKeysSet.has(k)) {
          // formData 中有对应的key才进行赋值
          values[k] = formData[k]
        }
      })
      // resetFields()
      setFieldsValue(values)
    })
  }

  /**
   * 根据配置获取渲染的组件类型
   */
  private getCompType(item: KeyValue): string {
    const result = 'a-input'
    if (dynamicCompMaps[item.type]) {
      return dynamicCompMaps[item.type].component
    }
    return result
  }

  /**
   * 获取组件formItem 的 decorator
   * 必须，否则无法注册到form上
   */
  private getDecorator(field: KeyValue) {
    const options: KeyValue = { initialValue: field.defaultValue }
    if (field.type === 'switch') {
      options.valuePropName = 'checked'
    }
    return [field.name, options]
  }

  /**
   * formItem 数值变化
   */
  private onFormValueChange(allValues: any) {
    this.form.validateFields((error: any) => {
      if (!error) {
        this.$emit('change', allValues) // onValuesChange 方法回调时只能用回调的参数，getFieldsValue等方法会有延迟，未生效
      }
    })
  }
}
</script>

<style lang="less" scoped>
.panel-title {
  font-weight: bolder;
  height: 40px;
  line-height: 40px;
  margin-top: 4px;
  position: relative;
  width: 100%;

  .anticon {
    font-size: 8px;
    font-weight: normal;
    height: 40px;
    line-height: 40px;
    position: absolute;
    right: 10px;
  }

  .panel-title-hr {
    background-color: #e9e9e9;
    height: 1px;
    left: -16px;
    position: absolute;
    right: -20px;
  }
}

/deep/ .ant-form-item-label {
  text-align: left;
}

/deep/ .ant-form-item.vertical {
  .ant-col {
    width: 100%;
  }
}

/deep/ .ant-form-item {
  margin-bottom: 0;
}

/deep/ .ant-form-item-label > label::after {
  content: '';
}

.as-fix-box {
  display: flex;
  flex-flow: column nowrap;

  /deep/ .ant-form-item-control-wrapper {
    width: 100%;

    .ant-form-item-children {
      background: #f1f1f1;
      box-sizing: border-box;
      display: block;
      padding-left: 8px;
      padding-top: 10px;
    }
  }
}

.filter-setting-form {
  &.fix {
    margin-top: 20px;
  }

  /deep/.ant-checkbox-group.as-charts {
    width: 100%;

    .ant-checkbox-wrapper {
      height: 32px;
      line-height: 32px;
      margin-left: 0;
      width: 100%;
    }
  }
}
</style>
